package com.fancy.application.sys.job.service.impl;

import cn.hutool.core.util.StrUtil;
import com.fancy.application.common.exception.FancyRuntimeException;
import com.fancy.application.common.service.impl.BaseService;
import com.fancy.application.sys.job.config.QuartzJobFactory;
import com.fancy.application.sys.job.entity.SysQuartzScheduleJob;
import com.fancy.application.sys.job.mapper.SysQuartzScheduleJobMapper;
import com.fancy.application.sys.job.service.ISysQuartzScheduleJobService;
import com.fancy.application.sys.job.service.ScheduleJobInService;
import lombok.extern.log4j.Log4j2;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
* fancycode自动生成v1.0
* @author wison
* 2019-12-29
*/
@Log4j2
@Service("sysQuartzScheduleJobService")
public class SysQuartzScheduleJobServiceImpl extends BaseService<SysQuartzScheduleJobMapper,SysQuartzScheduleJob> implements ISysQuartzScheduleJobService {
    @Autowired
    private Scheduler scheduler;

    @Autowired
    private ScheduleJobInService scheduleJobInService;

    /**
     * 获取所有的任务
     * @return
     */
    @Override
    public List<SysQuartzScheduleJob> getAllScheduleJob() {
        List<SysQuartzScheduleJob> jobList = new ArrayList<>();
        GroupMatcher<JobKey> matcher = GroupMatcher.anyGroup();
        try {
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
            for (JobKey key : jobKeys){
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(key);
                for (Trigger trigger: triggers){
                    SysQuartzScheduleJob scheduleJob = getScheduleJob(scheduler,key,trigger);
                    jobList.add(scheduleJob);
                }
            }
        } catch (SchedulerException e) {
            log.error("[SchedulerJobServiceImpl] get the jobKeys is error:{}",e);
            e.printStackTrace();
        }
        return jobList;
    }

    /**
     * 获取所有运行中的任务
     * @return
     * @throws SchedulerException
     */
    @Override
    public List<SysQuartzScheduleJob> getAllRunningJob() throws SchedulerException {

        List<JobExecutionContext> executionJobList = scheduler.getCurrentlyExecutingJobs();
        List<SysQuartzScheduleJob> jobList = new ArrayList<>();
        for (JobExecutionContext jobExecutionContext: executionJobList){
            JobDetail jobDetail = jobExecutionContext.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = jobExecutionContext.getTrigger();
            SysQuartzScheduleJob scheduleJob = getScheduleJob(scheduler,jobKey,trigger);
            jobList.add(scheduleJob);
        }
        return jobList;
    }

    /**
     * 更新新的任务或者添加一个新的任务
     * @param scheduleJob
     * @throws Exception
     */
    @Override
    public boolean saveOrUpdate(SysQuartzScheduleJob scheduleJob) {
        TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getFdJobName(),scheduleJob.getFdJobGroup());
        CronTrigger cronTrigger = null;
        try {
            cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (cronTrigger==null){
                addJob(scheduleJob);
            }else {
                updateJobCronSchedule(scheduleJob);
            }
        } catch (Exception e) {
            throw new FancyRuntimeException(e.getMessage());
        }

        return false;
    }

    /**
     * 停止运行任务
     * @param jobName
     * @param jobGroup
     * @throws SchedulerException
     */
    public void pauseJob(String jobName, String jobGroup) throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
        SysQuartzScheduleJob scheduleJob = scheduleJobInService.selectByJobNameAngJobGroup(jobName,jobGroup);
        scheduleJob.setFdJobStatus("PAUSED");
        scheduleJobInService.updateByPrimaryKey(scheduleJob);
        scheduler.pauseJob(jobKey);
    }

    /**
     * 删除一个任务
     * @param jobName
     * @param jobGroup
     * @throws SchedulerException
     */
    public void deleteJob(String jobName,String jobGroup) throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        scheduleJobInService.deleteByJobNameAndJobGroup(jobName,jobGroup);
        scheduler.deleteJob(jobKey);
    }

    /**
     * 运行一个任务
     * @param jobName
     * @param jobGroup
     * @throws SchedulerException
     */
    public void runOneJob(String jobName, String jobGroup) throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        SysQuartzScheduleJob scheduleJob = scheduleJobInService.selectByJobNameAngJobGroup(jobName, jobGroup);
        scheduleJob.setFdJobStatus("NORMAL");
        scheduleJobInService.updateByPrimaryKey(scheduleJob);
        scheduler.triggerJob(jobKey);
    }

    /**
     * 重启一个任务
     * @param jobName
     * @param jobGroup
     * @throws SchedulerException
     */
    public void resumeJob(String jobName, String jobGroup) throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
        SysQuartzScheduleJob scheduleJob = scheduleJobInService.selectByJobNameAngJobGroup(jobName,jobGroup);
        scheduleJob.setFdJobStatus("NORMAL");
        scheduleJobInService.updateByPrimaryKey(scheduleJob);
        scheduler.resumeJob(jobKey);
    }

    @Override
    public Boolean deleteJob(String id) {
        Boolean flag = Boolean.TRUE;
        SysQuartzScheduleJob job = this.getById(id);
        try {
            deleteJob(job.getFdJobName(),job.getFdJobGroup());
        } catch (SchedulerException e) {
            flag = Boolean.FALSE;
            log.error("任务删除失败",e);
            e.printStackTrace();
        }
        return flag;
    }


    /**
     * 添加任务
     * @param scheduleJob
     * @throws Exception
     */
    private void addJob(SysQuartzScheduleJob scheduleJob) throws Exception{
        checkNotNull(scheduleJob);
        if (StrUtil.isBlank(scheduleJob.getFdCronExpression())){
            throw new Exception("[SchedulerJobServiceImpl] CronExpression不能为空");
        }
        scheduleJob.setFdJobStatus("NORMAL");
        scheduleJobInService.insertSelective(scheduleJob);
        log.info("[SchedulerJobServiceImpl] the Primary key is:{}",scheduleJob.getFdId());

        scheduleJob.setFdId(scheduleJob.getFdId()+"");
        log.info("[SchedulerJobServiceImpl] the scheduleJob is:{}",scheduleJob);
        scheduleJobInService.updateByPrimaryKey(scheduleJob);
        JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class).withIdentity(scheduleJob.getFdJobName(),scheduleJob.getFdJobGroup()).build();
        jobDetail.getJobDataMap().put("scheduleJob",scheduleJob);
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getFdCronExpression());
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getFdJobName(),scheduleJob.getFdJobGroup())
                .withSchedule(cronScheduleBuilder).build();
        scheduler.scheduleJob(jobDetail,cronTrigger);

    }

    /**
     * 更新一个任务
     * @param scheduleJob
     * @throws Exception
     */
    private void updateJobCronSchedule(SysQuartzScheduleJob scheduleJob) throws Exception{
        checkNotNull(scheduleJob);
        if (StrUtil.isBlank(scheduleJob.getFdCronExpression())){
            throw new Exception("[SchedulerJobServiceImpl] CronExpression不能为空");
        }
        TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getFdJobName(),scheduleJob.getFdJobGroup());
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getFdCronExpression());
        cronTrigger = cronTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
        JobKey jobKey = JobKey.jobKey(scheduleJob.getFdJobName(),scheduleJob.getFdJobGroup());
        JobDetail jobDetail=scheduler.getJobDetail(jobKey);
        jobDetail.getJobDataMap().put("scheduleJob",scheduleJob);
        scheduler.rescheduleJob(triggerKey,cronTrigger);
        scheduleJobInService.updateByPrimaryKey(scheduleJob);

    }


    /**
     * 判断一个任务是否为空
     * @param scheduleJob
     */
    @Override
    public void checkNotNull(SysQuartzScheduleJob scheduleJob) {
        if (scheduleJob==null){
            throw new IllegalStateException("scheduleJob is null,Please check it");
        }
        if (scheduleJob.getFdJobName()==null || scheduleJob.getFdJobName().equals("")){
            throw new IllegalStateException("the jobName of scheduleJob is null,Please check it");
        }
        if (scheduleJob.getFdJobGroup()==null || scheduleJob.getFdJobGroup().equals("")){
            throw new IllegalStateException("the jobGroup of scheduleJob is null,Please check it");
        }
        if (scheduleJob.getFdBeanName()==null || scheduleJob.getFdBeanName().equals("")){
            throw new IllegalStateException("the BeanName of scheduleJob is null,Please check it");
        }


    }



    private SysQuartzScheduleJob getScheduleJob(Scheduler schedule, JobKey jobKey, Trigger trigger){
        SysQuartzScheduleJob scheduleJob = new SysQuartzScheduleJob();
        try {
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            scheduleJob = (SysQuartzScheduleJob)jobDetail.getJobDataMap().get("scheduleJob");
            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
            scheduleJob.setFdJobStatus(triggerState.name());
            scheduleJob.setFdJobName(jobKey.getName());
            scheduleJob.setFdJobGroup(jobKey.getGroup());
            if (trigger instanceof CronTrigger){
                CronTrigger cronTrigger = (CronTrigger) trigger;
                scheduleJob.setFdCronExpression(cronTrigger.getCronExpression());
            }

        } catch (Exception e) {
            log.error("[SchedulerJobServiceImpl] method getScheduleJob get JobDetail error:{}",e);
        }
        return scheduleJob;
    }
}
